package com.alibaba.citrus.cr.mn.order.center.facade.function.check;

import com.alibaba.citrus.cr.common.enums.ordercenter.*;
import com.alibaba.citrus.cr.common.exception.FunctionException;
import com.alibaba.citrus.cr.common.util.DateUtils;
import com.alibaba.citrus.cr.mn.order.center.common.util.AssertUtils;
import com.alibaba.citrus.cr.mn.order.center.common.util.JsonUtils;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.BaseDataServiceAdapter;
import com.alibaba.citrus.cr.mn.order.center.facade.adapter.BusinessUnitAbilityAdapter;
import com.epoch.app.mnordercenter.model.dto.DictionaryResponse;
import com.epoch.app.mnordercenter.model.dto.Modifiers;
import com.epoch.app.mnordercenter.orderbaserequest.OrderBizUpdateRequest;
import com.epoch.app.mnordercenter.orderbaserequest.OrderBizUpdateResponse;
import com.epoch.app.mnordercenter.orderbaserequest.OrderLineAtomUpdateRequest;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author zhangxiaorui
 * @ClassName SalesOrderCreateParamsCheck
 * @description: TODO
 * @date 2023/05/11 16:35
 * @version: 1.0
 */
@Service
public class SalesOrderUpdateParamsBizCheck {

    @Resource
    private BaseDataServiceAdapter baseDataServiceAdapter;
    @Resource
    private CommonCheck commonCheck;
    @Resource
    private BusinessUnitAbilityAdapter businessUnitAbilityAdapter;

    public void paramsInvalidCheck(OrderBizUpdateRequest request, OrderBizUpdateResponse response) {
        // 空值校验
        paramsNotBlankCheck(request, response);
        // 长度校验
        paramsLengthCheck(request, response);
        // 枚举校验（合法性校验）
        paramsEnumDictCheck(request, response);
    }

    public void paramsEnumDictCheck(OrderBizUpdateRequest request, OrderBizUpdateResponse response) {
        // 系统来源
        List<DictionaryResponse> fromSysResponseList = baseDataServiceAdapter.queryDictionarys(DictionaryTypeEnum.FROM_SYS.getCode());
        Map<String, DictionaryResponse> fromSysMap = fromSysResponseList.stream().collect(Collectors.toMap(DictionaryResponse::getCode, Function.identity(), (k1, k2) -> k2));
        //业态
        List<DictionaryResponse> businessTypeResponseList = baseDataServiceAdapter.queryDictionarys(DictionaryTypeEnum.BUSINESS_TYPE.getCode());
        Map<String, DictionaryResponse> businessTypeMap = businessTypeResponseList.stream().collect(Collectors.toMap(DictionaryResponse::getCode, Function.identity(), (k1, k2) -> k2));
        //校验修改人
        List<String> modifierCodeList = Collections.singletonList(request.getModifierCode());
        Map<String, Modifiers> modifiersMap = commonCheck.invalidModifierList(modifierCodeList);

        if (fromSysMap.get(request.getFromSys()) == null) {
            throw new FunctionException("OC-01-001-01-15-006", "来源系统编码");
        }
        if (businessTypeMap.get(request.getBusinessType()) == null) {
            throw new FunctionException("OC-01-001-01-15-006", "业态编码");
        }
        Modifiers modifiers = modifiersMap.get(request.getModifierCode());
        if (Objects.isNull(modifiers)) {
            throw new FunctionException("OC-01-001-01-16-041");
        }
        AssertUtils.isTrue(!businessUnitAbilityAdapter.checkBusinessUnitCode(request.getBusinessUnitCode()), "OC-01-001-01-15-006", "业务单元编码");
        request.setModifierName(modifiers.getName());
        // 校验配送方式编码
        if (StringUtils.isNotBlank(request.getDeliveryMethodCode())) {
            SalesOrderDeliveryMethodEnum salesOrderDeliveryMethodEnum = SalesOrderDeliveryMethodEnum.of(request.getDeliveryMethodCode());
            Optional.ofNullable(salesOrderDeliveryMethodEnum).orElseThrow(() -> new FunctionException("OC-01-001-01-15-006", "配送方式编码"));
            request.setDeliveryMethodName(salesOrderDeliveryMethodEnum.getDesc());
        }
        // 校验订单原因编码
        if (StringUtils.isNotBlank(request.getOrderReasonCode())) {
            SalesOrderReasonEnum salesOrderReasonEnum = SalesOrderReasonEnum.of(request.getOrderReasonCode());
            Optional.ofNullable(salesOrderReasonEnum).orElseThrow(() -> new FunctionException("OC-01-001-01-15-006", "订单原因编码"));
            request.setOrderReasonName(salesOrderReasonEnum.getDesc());
        }
        // 校验履约方式编码
        if (StringUtils.isNotBlank(request.getFulfillmentTypeCode())) {
            //履约方式
            List<DictionaryResponse> fulfillmentTypeList = baseDataServiceAdapter.queryDictionarys(DictionaryTypeEnum.COMPANY_SALE_FULFILLMENT_TYPE.getCode());
            Map<String, DictionaryResponse> fulfillmentTypeMap = fulfillmentTypeList.stream().collect(Collectors.toMap(DictionaryResponse::getCode, Function.identity(), (k1, k2) -> k2));
            Optional.ofNullable(fulfillmentTypeMap.get(request.getFulfillmentTypeCode())).orElseThrow(() -> new FunctionException("OC-01-001-01-15-006", "履约方式"));
        }
        if (StringUtils.isNotBlank(request.getFulfillmentPriority())) {
            Optional.ofNullable(FulfillmentPriorityEnum.of(request.getFulfillmentPriority())).orElseThrow(() -> new FunctionException("OC-01-001-01-15-006", "履约优先级"));
        }
        if (CollectionUtils.isNotEmpty(request.getOrderBizTag())) {
            Set<String> removeRepeat = new HashSet<>(request.getOrderBizTag());
            if (removeRepeat.size() != request.getOrderBizTag().size()) {
                throw new FunctionException("OC-01-001-01-15-016", "订单标签");
            }
            request.getOrderBizTag().parallelStream().forEach(orderBizTag -> {
                Optional.ofNullable(OrderBizTagEnum.of(orderBizTag)).orElseThrow(() -> new FunctionException("OC-01-001-01-15-006", "订单标签"));
            });
        }
        request.getOrderDetails().forEach(p -> {
            if (StringUtils.isNotBlank(p.getConfirmQuantity())) {
                AssertUtils.isWholeNumber(p.getConfirmQuantity(), false, "OC-01-001-01-15-009", "确认数量", "确认数量须为正整数");
                AssertUtils.isTrue(BigDecimal.ZERO.compareTo(new BigDecimal(p.getConfirmQuantity())) >= 0, "OC-01-001-01-15-009", "确认数量", "确认数量须为正整数");
                AssertUtils.isTrue(new BigDecimal("2147483647").compareTo(new BigDecimal(p.getConfirmQuantity())) < 0, "OC-01-001-01-15-009", "确认数量", "最大2147483647");
            }
            if (StringUtils.isNotBlank(p.getSourceQuantity())) {
                AssertUtils.isWholeNumber(p.getSourceQuantity(), false, "OC-01-001-01-15-009", "来单数量", "来单数量须为正整数");
                AssertUtils.isTrue(BigDecimal.ZERO.compareTo(new BigDecimal(p.getSourceQuantity())) >= 0, "OC-01-001-01-15-009", "来单数量", "来单数量须为正整数");
                AssertUtils.isTrue(new BigDecimal("2147483647").compareTo(new BigDecimal(p.getSourceQuantity())) < 0, "OC-01-001-01-15-009", "来单数量", "最大2147483647");
            }
            if (StringUtils.isNotBlank(p.getSourcePrice())) {
                AssertUtils.isNumber(p.getSourcePrice(), false, "OC-01-001-01-15-006", "来单价格");
                AssertUtils.isTrue(new BigDecimal("2147483647").compareTo(new BigDecimal(p.getSourcePrice())) < 0, "OC-01-001-01-15-009", "来单价格", "最大2147483647");
            }
            if (StringUtils.isNotBlank(p.getProductionDate())) {
                AssertUtils.timeFormatCheck(p.getProductionDate(), null, "生产日期", null, AssertUtils.TYPE_DATE);
            }
        });
    }

    public void paramsNotBlankCheck(OrderBizUpdateRequest request, OrderBizUpdateResponse response) {
        AssertUtils.isTrue(StringUtils.isBlank(request.getFromSys()), "OC-01-001-01-15-001", "来源系统编码");
        AssertUtils.isTrue(StringUtils.isBlank(request.getBusinessType()), "OC-01-001-01-15-001", "业态编码");
        AssertUtils.isTrue(StringUtils.isBlank(request.getBusinessUnitCode()), "OC-01-001-01-15-001", "业务单元编码");
        AssertUtils.isTrue(StringUtils.isBlank(request.getSalesOrderNo()), "OC-01-001-01-15-001", "销售订单号");
        AssertUtils.isTrue(StringUtils.isBlank(request.getModifierCode()), "OC-01-001-01-15-001", "修改人工号");
        if (StringUtils.isNotBlank(request.getReceiveWarehouseCode())
                || StringUtils.isNotBlank(request.getReceiveFactoryCode())
                || StringUtils.isNotBlank(request.getReceiveStockCode())) {
            if (StringUtils.isBlank(request.getReceiveWarehouseCode())) {
                AssertUtils.isTrue(StringUtils.isBlank(request.getReceiveFactoryCode()), "OC-01-001-01-15-001", "收货工厂编码");
                AssertUtils.isTrue(StringUtils.isBlank(request.getReceiveStockCode()), "OC-01-001-01-15-001", "收货库存地点编码");
            }
        }
        if (CollectionUtils.isEmpty(request.getOrderDetails())) {
            throw new FunctionException("OC-01-001-01-15-001", "单据明细");
        }

        request.getOrderDetails().forEach(orderDetail -> {
            AssertUtils.isTrue(StringUtils.isBlank(orderDetail.getSourceLineNum()), "OC-01-001-01-15-001", "来源单行号");
            if (StringUtils.isBlank(orderDetail.getLineNum())) {
                // 新增明细行校验
                if (OrderCategoryEnum.GROUP.getCode().equals(request.getOrderCategoryCode()) || OrderCategoryEnum.STOCK.getCode().equals(request.getOrderCategoryCode()) ) {
                    AssertUtils.isTrue(StringUtils.isBlank(orderDetail.getProductionDate()), "OC-01-001-01-15-001", "生产日期");
                }
                AssertUtils.isTrue(StringUtils.isBlank(orderDetail.getProductQuantity()), "OC-01-001-01-15-001", "销售数量");
                AssertUtils.isTrue(StringUtils.isBlank(orderDetail.getSalesUnitCode()), "OC-01-001-01-15-001", "销售单位编码");
                AssertUtils.isTrue(StringUtils.isBlank(orderDetail.getProductCode()), "OC-01-001-01-15-001", "物料编码");
                // 新增明细行场景下，【发货仓编码】与【工厂+库存地点】二选一必填
                if (StringUtils.isBlank(orderDetail.getShippingWarehouseCode())) {
                    if (StringUtils.isBlank(orderDetail.getDeliveryFactoryCode()) && StringUtils.isBlank(orderDetail.getStockCode())) {
                        throw new FunctionException("OC-01-001-01-15-010", "发货逻辑仓库编码、发货工厂编码、发货库存地点编码");
                    }
                    AssertUtils.isTrue(StringUtils.isBlank(orderDetail.getDeliveryFactoryCode()), "OC-01-001-01-15-001", "发货工厂编码");
                    AssertUtils.isTrue(StringUtils.isBlank(orderDetail.getStockCode()), "OC-01-001-01-15-001", "发货库存地点编码");
                }
            } /*else {
                // 修改明细行校验
                if (StringUtils.isBlank(orderDetail.getShippingWarehouseCode())) {
                    AssertUtils.isTrue(StringUtils.isBlank(orderDetail.getDeliveryFactoryCode()), "OC-01-001-01-15-001", "发货工厂编码");
                    AssertUtils.isTrue(StringUtils.isBlank(orderDetail.getStockCode()), "OC-01-001-01-15-001", "发货库存地点编码");
                }
            }*/
        });
    }

    public void paramsLengthCheck(OrderBizUpdateRequest request, OrderBizUpdateResponse response) {
        AssertUtils.lengthCheck(request.getFromSys(), 50, true, "OC-01-001-01-15-004", "来源系统编码");
        AssertUtils.lengthCheck(request.getBusinessType(), 10, true, "OC-01-001-01-15-004", "业态编码");
        AssertUtils.isNumber(request.getBusinessType(), true, "OC-01-001-01-15-006", "业态编码");
        AssertUtils.lengthCheck(request.getBusinessUnitCode(), 50, true, "OC-01-001-01-15-004", "业务单元编码");
        AssertUtils.lengthCheck(request.getSalesOrderNo(), 50, true, "OC-01-001-01-15-004", "订单单号");
        AssertUtils.lengthCheck(request.getModifierCode(), 50, true, "OC-01-001-01-15-004", "修改人工号");
        AssertUtils.lengthCheck(request.getSalesChannelCode(), 50, false, "OC-01-001-01-15-004", "销售渠道编码");
        AssertUtils.lengthCheck(request.getSalesChannelName(), 50, false, "OC-01-001-01-15-004", "销售渠道名称");
        AssertUtils.lengthCheck(request.getSalesDepartmentCode(), 50, false, "OC-01-001-01-15-004", "销售部门编码");
        AssertUtils.lengthCheck(request.getSalesDepartmentName(), 50, false, "OC-01-001-01-15-004", "销售部门名称");
        AssertUtils.lengthCheck(request.getShipToPartyCode(), 50, false, "OC-01-001-01-15-004", "客户送达方编码");
//        AssertUtils.lengthCheck(request.getShipToPartyName(), 50, "OC-01-001-01-15-004", "客户送达方名称");
        AssertUtils.lengthCheck(request.getReceiveWarehouseCode(), 50, false, "OC-01-001-01-15-004", "收货仓编码");
        AssertUtils.lengthCheck(request.getReceiveFactoryCode(), 50, false, "OC-01-001-01-15-004", "收货工厂编码");
        AssertUtils.lengthCheck(request.getReceiveStockCode(), 50, false, "OC-01-001-01-15-004", "收货库存地点编码");
        AssertUtils.lengthCheck(request.getCostCenterCode(), 50, false, "OC-01-001-01-15-004", "成本中心编码");
        if (StringUtils.isNotBlank(request.getExpectedDeliveryDate())) {
            AssertUtils.lengthCheck(request.getExpectedDeliveryDate(), 10, false, "OC-01-001-01-15-004", "期望交货日期");
            AssertUtils.isTrue(!DateUtils.isDateFormat(request.getExpectedDeliveryDate()), "OC-00-001-01-15-001", "期望交货日期");
        }
        AssertUtils.lengthCheck(request.getDeliveryMethodCode(), 50, false, "OC-01-001-01-15-004", "配送方式编码");
        AssertUtils.lengthCheck(request.getOrderReasonCode(), 50, false, "OC-01-001-01-15-004", "订单原因编码");
        AssertUtils.lengthCheck(request.getBizFeatures(), 1024, false, "OC-01-001-01-15-004", "扩展字段");
        AssertUtils.lengthCheck(request.getNote(), 255, false, "OC-01-001-01-15-004", "订单头备注");
        // 校验扩展字段是否为JSON格式
        if (StringUtils.isNotBlank(request.getBizFeatures())) {
            AssertUtils.isTrue(!JsonUtils.isValidJson(request.getBizFeatures()), "OC-00-001-01-15-001", "主单扩展字段");
        }
        // AssertUtils.isBoolean(request.getCheckCredit(), Boolean.FALSE, "是否校验信贷");
        // AssertUtils.isBoolean(request.getCheckStock(), Boolean.FALSE, "是否校验库存");
        AssertUtils.isTrue(request.getOrderDetails().size() > 100, "OC-01-001-01-15-004", "订单明细集合", request.getOrderDetails().size(), 100);

        AssertUtils.lengthCheck(request.getFulfillmentPriority(), 10, false, "OC-01-001-01-15-004", "履约优先级");
        if (CollectionUtils.isNotEmpty(request.getOrderBizTag())) {
            AssertUtils.isTrue(request.getOrderBizTag().size() > 10, "OC-01-001-01-15-004", "订单标签集合", request.getOrderBizTag().size(), 10);
            request.getOrderBizTag().forEach(param -> {
                AssertUtils.lengthCheck(param, 50, false, "OC-01-001-01-15-004", "订单标签");
            });
        }
        AssertUtils.lengthCheck(request.getKaArea(), 50, false, "OC-01-001-01-15-004", "KA大区");
        AssertUtils.lengthCheck(request.getKaSystem(), 50, false, "OC-01-001-01-15-004", "KA系统");
        if (StringUtils.isNotBlank(request.getSourceOrderTime())) {
            AssertUtils.lengthCheck(request.getSourceOrderTime(), 19, false, "OC-01-001-01-15-004", "来单时间");
            AssertUtils.isTrue(!DateUtils.isDateTimeFormat(request.getSourceOrderTime()), "OC-00-001-01-15-001", "来单时间");
        }

        request.getOrderDetails().forEach(orderDetail -> {
            AssertUtils.lengthCheck(orderDetail.getLineNum(), 10, false, "OC-01-001-01-15-004", "销售订单明细行号");
            AssertUtils.lengthCheck(orderDetail.getSourceLineNum(), 10, "OC-01-001-01-15-004", "来源单行号");
            if (StringUtils.isNotBlank(orderDetail.getProductQuantity())) {
                AssertUtils.lengthCheck(orderDetail.getProductQuantity(), 10, false, "OC-01-001-01-15-004", "销售数量");
                AssertUtils.isWholeNumber(orderDetail.getProductQuantity(), false, "OC-01-001-01-15-009", "销售数量", "销售数量须为正整数");
                AssertUtils.isTrue(BigDecimal.ZERO.compareTo(new BigDecimal(orderDetail.getProductQuantity())) >= 0, "OC-01-001-01-15-009", "销售数量", "销售数量须为正整数");
                AssertUtils.isTrue(new BigDecimal("2147483647").compareTo(new BigDecimal(orderDetail.getProductQuantity())) < 0, "OC-01-001-01-15-009", "销售数量", "最大2147483647");
            }
            AssertUtils.lengthCheck(orderDetail.getProductCode(), 50, false, "OC-01-001-01-15-004", "物料编码");
            AssertUtils.lengthCheck(orderDetail.getSalesUnitCode(), 50, false, "OC-01-001-01-15-004", "销售单位编码");
            AssertUtils.lengthCheck(orderDetail.getShippingWarehouseCode(), 50, false, "OC-01-001-01-15-004", "发货仓库编码");
            AssertUtils.lengthCheck(orderDetail.getDeliveryFactoryCode(), 50, false, "OC-01-001-01-15-004", "发货工厂编码");
            AssertUtils.lengthCheck(orderDetail.getStockCode(), 50, false, "OC-01-001-01-15-004", "发货库存地点编码");
            AssertUtils.lengthCheck(orderDetail.getProductionDate(), 10, false, "OC-01-001-01-15-004", "生产日期");
            AssertUtils.lengthCheck(orderDetail.getNote(), 255, false, "OC-01-001-01-15-004", "订单行备注");
            AssertUtils.lengthCheck(orderDetail.getBizFeatures(), 1024, false, "OC-01-001-01-15-004", "扩展字段");
            // 校验扩展字段是否为JSON格式
            if (StringUtils.isNotBlank(orderDetail.getBizFeatures())) {
                AssertUtils.isTrue(!JsonUtils.isValidJson(orderDetail.getBizFeatures()), "OC-00-001-01-15-001", "子单扩展字段");
            }
            if (StringUtils.isNotBlank(orderDetail.getConfirmQuantity())) {
                AssertUtils.lengthCheck(orderDetail.getConfirmQuantity(), 10, false, "OC-01-001-01-15-004", "确认数量");
                AssertUtils.isWholeNumber(orderDetail.getConfirmQuantity(), false, "OC-01-001-01-15-009", "确认数量", "确认数量须为正整数");
                AssertUtils.isTrue(BigDecimal.ZERO.compareTo(new BigDecimal(orderDetail.getConfirmQuantity())) >= 0, "OC-01-001-01-15-009", "确认数量", "确认数量须为正整数");
                AssertUtils.isTrue(new BigDecimal("2147483647").compareTo(new BigDecimal(orderDetail.getConfirmQuantity())) < 0, "OC-01-001-01-15-009", "确认数量", "最大2147483647");
            }
            AssertUtils.lengthCheck(orderDetail.getSourceQuantity(), 10, false, "OC-01-001-01-15-004", "来单数量");
            AssertUtils.lengthCheck(StringUtils.isBlank(orderDetail.getSourcePrice()) ? null : orderDetail.getSourcePrice().split("\\.")[0], 10, false, "OC-01-001-01-15-004", "来单价格");
            AssertUtils.lengthCheck(orderDetail.getSourceUnit(), 50, false, "OC-01-001-01-15-004", "来单单位");
        });

        // 校验单据明细行号是否重复
        List<String> sameSourceLines = request.getOrderDetails().stream()
                .map(OrderLineAtomUpdateRequest::getSourceLineNum)
                .collect(Collectors.toMap(p -> p, p -> 1, Integer::sum))
                .entrySet().stream().filter(entry -> entry.getValue() > 1)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(sameSourceLines)) {
            throw new FunctionException("OC-01-001-01-15-002", "来源单行号", StringUtils.join(sameSourceLines, ","));
        }
    }

}
